package Server_Netty.UDP;

import Server_Netty.TCP.TCPServer;
import Server_Netty.DataCallBackClass;
import Server_Netty.Main_Send_Receive_Manager;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.ReferenceCountUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class UDPServer {
    public static final Logger LOGGER= LoggerFactory.getLogger(TCPServer.class);

    public int UDP_RoleId = 0;
    private short Test_Count=0;
    public int UDP_port = 0;
    public UDPServer(int RoleId, int port) {
        UDP_RoleId=RoleId;
        UDP_port=port;

    }
    public LinkedBlockingQueue<DataCallBackClass> ReceiveDataQueue = new LinkedBlockingQueue<DataCallBackClass>();

    public boolean bind(String local_address, int port) throws Exception{
        boolean bOK=false;
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();

            b.group(group)
                    .channel(NioDatagramChannel.class)
                    .handler(new ChannelInitializer<NioDatagramChannel>() {
                        @Override
                        protected void initChannel(NioDatagramChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();

                            pipeline.addLast( new UDPData_SeverHandler());//数据处理器

                            pipeline.addLast("timeout", new IdleStateHandler(180, 0, 0,
                                    TimeUnit.SECONDS));// //此两项为添加心跳机制,60秒查看一次在线的客户端channel是否空闲
                        }
                    })
                    .option(ChannelOption.SO_RCVBUF, 1024 * 1500)// 设置UDP读缓冲区
                    .option(ChannelOption.SO_SNDBUF, 1024 * 1500);// 设置UDP写缓冲区;

            LOGGER.info("port:" + port + "[  UDP 启动了]");
            b.bind(local_address, port).sync().channel().closeFuture().sync();

            bOK=true;
        }finally {
            group.shutdownGracefully();

            LOGGER.info("port:" + port + "[  UDP 关闭了]");
            bOK=false;
        }
        return bOK;
    }


    class UDPData_SeverHandler extends SimpleChannelInboundHandler<DatagramPacket>  {

        public UDPData_SeverHandler() {

        }

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
            // 读取收到的数据

            ByteBuf buf = (ByteBuf) packet.copy().content();
            byte[] req = new byte[buf.readableBytes()];
            buf.readBytes(req);
            ReferenceCountUtil.release(buf);
            DataCallBackClass UndealData=new DataCallBackClass(UDP_RoleId, (short)req.length, req);
            //接收数据包大于30000个就丢弃
            if(ReceiveDataQueue.size()<=30000){
                ReceiveDataQueue.offer(UndealData);
                if (Test_Count==32766){
                    LOGGER.info("UDP_RoleId:"+UDP_RoleId+"，数据包又接收32767个");
                    Test_Count=0;
                }else {
                    Test_Count++;
                }

            }

        }


        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            //   System.out.println("UDP_RoleId:"+UDP_RoleId+"客户端已连接");
            if (Main_Send_Receive_Manager.RoleID_map.get(UDP_RoleId) != null && Main_Send_Receive_Manager.RoleID_map.get(UDP_RoleId).equals(ctx)) {
                LOGGER.info("UDP_RoleId:"+UDP_RoleId+"的map映射已存在");
            } else {
                Main_Send_Receive_Manager.RoleID_map.put(UDP_RoleId, ctx);
                LOGGER.info(UDP_RoleId+"UDP_map.put(UDP_RoleId, ctx);");
            }


            //添加ROLEID与队列映射
            if (Main_Send_Receive_Manager.RoleID_ReceiveQueue.get(UDP_RoleId)==null){
                Main_Send_Receive_Manager.RoleID_ReceiveQueue.put(UDP_RoleId,ReceiveDataQueue);

            }



        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            LOGGER.info("UDP_RoleId:"+UDP_RoleId+"客户端已断开");
            removeChannnelMap();
            LOGGER.info("UDP_RoleId:"+UDP_RoleId+"的map映射已删除");
            super.channelInactive(ctx);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            LOGGER.info("UDP,exceptionCaught的错误码："+cause.getCause());
            //  super.exceptionCaught(ctx, cause);
            Channel channel = ctx.channel();
            if(channel.isActive())
                ctx.close();
        }

        /** 删除map中ChannelHandlerContext*/
        private void removeChannnelMap() {
            if (Main_Send_Receive_Manager.RoleID_map.get(UDP_RoleId) != null ) {
                Main_Send_Receive_Manager.RoleID_map.remove(UDP_RoleId);
            }
        }
    }


}